#!/usr/bin/env bash

include "libs/database.sh"
include "libs/output.sh"
include "libs/test.sh"

function ohos:cd_repo()
{
    if ! ohos:have_repo; then
        output:loge "这个命令需要仓库"
        return 1
    fi

    local repo_path="$(ohos:get_repo_path)"
    if [ -d "$repo_path" ]; then
        cd "$repo_path"
    else
        output:loge "${repo_path}不是目录，请重新配置"
        return 1
    fi
}

function ohos:define_global_data()
{
    database:global_load
    OHOS_DOCKER_USE="$(database:global_get use_docker)"
    OHOS_DOCKER_USE="${OHOS_DOCKER_USE:-"true"}"

    OHOS_WINDOW_USE="$(database:global_get use_window)"
    OHOS_WINDOW_USE="${OHOS_WINDOW_USE:-"true"}"

    OHOS_IMAGE_NAME=${OHOS_IMAGE_NAME:-"hi3516dv300-\$(date +\"%Y-%m-%d_%H-%M-%S\")"}
    OHOS_IMAGE_DIR=${OHOS_IMAGE_DIR:-"$HOME"}
    OHOS_REMOVE_OUT=${OHOS_REMOVE_OUT:-"0"}

    DOCKER_ARGS=()
    DOCKER_ARGS+=(--ccache)
    DOCKER_CWD="."

    # $1: path_prefix
    function ohos:get_env()
    {
        echo -en "export CCACHE_DIR=$1/.ccache"

        # for nodejs
        echo -en ";export PATH=\"\$PATH:$1/prebuilts/build-tools/common/nodejs/node-v12.18.4-linux-x64/bin/\""

        # for gn, ninja
        echo -en ";export PATH=\"\$PATH:/std/prebuilts/build-tools/linux-x86/bin/\""
    }

    PRODUCT=Hi3516DV300
    JS_PREBUILTS=prebuilts/build-tools/common/js-framework
    JS_NODE=prebuilts/build-tools/common/nodejs/node-v12.18.4-linux-x64
    MAIN_BRANCH=m/master
    COMMAND_CURDIR="$(pwd)"
    OHOS_BINUTILS="./prebuilts/gcc/linux-x86/arm/gcc-linaro-7.5.0-arm-linux-gnueabi/bin/arm-linux-gnueabi-"
    OHOS_BINUTILS="./prebuilts/gcc/linux-x86/aarch64/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-"
    OHOS_OUT_DIR=out/ohos-arm-release
    OHOS_NINJA_ERROR_NUM=8
}

function ohos:have_repo()
{
    [ "$REPO_PATH" != "" ]
}

function ohos:get_repo_name()
{
    echo $CONTAINER_NAME
}

function ohos:get_repo_path()
{
    echo $REPO_PATH
}

function ohos:define_repo_data()
{
    CONTAINER_NAME="$1"
    REPO_PATH="$2"
    ohos:cd_repo 1>/dev/null 2>&1 || return
    if [ -e out/sdk/ohos-sdk/linux/toolchains/hdc_std ]; then
        OHOS_HDC=$(pwd)/out/sdk/ohos-sdk/linux/toolchains/hdc_std
    elif [ -e developtools/hdc_standard/prebuilt/linux/hdc_std ]; then
        OHOS_HDC=$(pwd)/developtools/hdc_standard/prebuilt/linux/hdc_std
    fi

    for (( i = 0; i < $(database:global_get repo_number); i++ )); do
        [ "$(database:global_array_get repo_name $i)" == "$CONTAINER_NAME" ] || continue
        [ "$(database:global_array_get repo_product $i)" != "" ] || continue
        PRODUCT="$(database:global_array_get repo_product $i)"
    done
    cd - 1>/dev/null
}

function ohos:define_command_data()
{
    if [ "$OHOS_HDC" == "" ]; then
        if which hdc 1>/dev/null 2>&1; then
            OHOS_HDC=$(which hdc)
        elif which hdc_std 1>/dev/null 2>&1; then
            OHOS_HDC=$(which hdc_std)
        fi
    fi

    if ohos:have_repo; then
        if [ -f $REPO_PATH/productdefine/common/products/$PRODUCT.json ]; then
            local device="$(cat $REPO_PATH/productdefine/common/products/$PRODUCT.json | grep "product_device" | cut -d\" -f4)"
            OHOS_OUT_DIR=out/$device
            if [ "$device" == "sdk" ]; then
                OHOS_BINUTILS="./prebuilts/mingw-w64/ohos/linux-x86_64/clang-mingw/bin/llvm-"
            fi
        fi
    fi
}

function ohos:check_param()
{
    local param_name="$1"
    if [ "${!param_name}" = "" ]; then
        false || report 需要一个名叫$param_name的参数
        return 1
    fi
    return 0
}

# ohos:buildlog {{{

# function:
#   bool   buildlog_init()
#   string buildlog_display(int)
#   string buildlog_displays()
#   int    buildlog_count()
#   string buildlog_filename(int)
#   string buildlog_command(int)
#
# data:
#   ohos_buildlog_fileno: Array(begin, end, begin, end, ...)
declare ohos_buildlog_fileno

# retval: [0]success, [1]no error be found [2]no such file
# stdout: -
# params: ()
# env_params: (test_build_log)
function ohos:buildlog_init()
{
    ohos_buildlog_fileno=()
    [ "$OHOS_OUT_DIR" != "" ] || ohos:define_global_data
    ohos:cd_repo || return
    ohos_build_log=${test_build_log:-$REPO_PATH/$OHOS_OUT_DIR/build.log}
    if [ ! -f "$ohos_build_log" ]; then
        return 2
    fi

    local length

    local gn_error_lineno=($(egrep -n "^ERROR " "$ohos_build_log" | cut -d: -f1))
    for gn_error in ${gn_error_lineno[*]}; do
        ohos_buildlog_fileno+=($gn_error)
        length=$(sed -n "$((gn_error)),\$p" $ohos_build_log | egrep -m 1 "^$" -n | cut -d: -f 1)
        if [ "$length" == "" ]; then
            length="5"
        fi
        ohos_buildlog_fileno+=($((length - 1)))
    done

    local failed_lineno=($(egrep -n "^FAILED: " "$ohos_build_log" | cut -d: -f1))
    for line in ${failed_lineno[*]}; do
        ohos_buildlog_fileno+=($line)
        length=$(sed -n "$((line)),\$p" $ohos_build_log | egrep -m 1 "^\[[0-9]+/[0-9]+\] " -n | cut -d: -f 1)
        if [ "$length" == "" ]; then
            length=$(sed -n "$((line)),\$p" $ohos_build_log | egrep -m 1 "^ninja: build stopped" -n | cut -d: -f 1)
        fi
        ohos_buildlog_fileno+=($((length - 2)))
    done
    [ "${#ohos_buildlog_fileno[*]}" != "0" ]
}

function ohos:buildlog_init:test()
{
    REPO_PATH="$(pwd)"
    CONTAINER_NAME="test"
    test_build_log=$OHOS_TOOL/snapshot
    test:should_return 2 ohos:buildlog_init

    test_build_log=$OHOS_TOOL/snapshot/build_log_0
    test:should_return_true ohos:buildlog_init
}
test:register_test ohos:buildlog_init:test

# retval: [0]success
# stdout: string(error log content)
# params: (index)
# env_params: -
function ohos:buildlog_display()
{
    local start=$((ohos_buildlog_fileno[$1 * 2 + 0]))
    local length=$((ohos_buildlog_fileno[$1 * 2 + 1]))
    sed -n "$start,+${length}p" "$ohos_build_log"
}

function ohos:buildlog_display:test()
{
    for (( i = 0; i < $(ohos:buildlog_count); i++ )) do
        test:run_snapshot ohos:buildlog_display $i
    done
}
test:register_test ohos:buildlog_display:test

# retval: [0]success
# stdout: string(error log content)
# params: ()
# env_params: -
function ohos:buildlog_displays()
{
    for (( i = 0; i < $(ohos:buildlog_count); i++ )); do
        ohos:buildlog_display $i
    done
}

function ohos:buildlog_displays:test()
{
    test:run_snapshot ohos:buildlog_displays
}
test:register_test ohos:buildlog_displays:test

# retval: [0]success
# stdout: int(error log count)
# params: ()
# env_params: -
function ohos:buildlog_count()
{
    echo $((${#ohos_buildlog_fileno[*]} / 2))
}

function ohos:buildlog_count:test()
{
    test:run_snapshot ohos:buildlog_count
}
test:register_test ohos:buildlog_count:test

# retval: [0]success [1]not exist
# stdout: int(error log's filename)
# params: (index)
# env_params: -
function ohos:buildlog_filename()
{
    local content=$(sed -n "$((ohos_buildlog_fileno[$1 * 2]))p" "$ohos_build_log")
    if [[ "$content" =~ (^FAILED:) ]]; then
        echo "$content" | cut -d' ' -f 2
    else
        return 1
    fi
}

function ohos:buildlog_filename:test()
{
    for (( i = 0; i < $(ohos:buildlog_count); i++ )) do
        test:run_snapshot ohos:buildlog_filename $i
    done
}
test:register_test ohos:buildlog_filename:test

# retval: [0]success [1]not exist
# stdout: int(error log's command)
# params: (index)
# env_params: -
function ohos:buildlog_command()
{
    local content=$(sed -n "$((ohos_buildlog_fileno[$1 * 2]))p" "$ohos_build_log")
    if [[ "$content" =~ (^FAILED:) ]]; then
        sed -n "$((ohos_buildlog_fileno[$1 * 2] + 1))p" "$ohos_build_log"
    else
        return 1
    fi
}

function ohos:buildlog_command:test()
{
    for (( i = 0; i < $(ohos:buildlog_count); i++ )) do
        test:run_snapshot ohos:buildlog_command $i
    done
}
test:register_test ohos:buildlog_command:test

# ohos:buildlog }}}
